package com.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;


/**
 * @SpringBootApplication :表示这是一个springboot的应用/项目
 * @Author: 张锦波
 * @Date: 2024/8/4 21:11
 * @Version: 1.0
 */
@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动springboot的应用程序/项目
        //当我们启动这个方法时，怎么就启动我们内置的tomcat?
        /**
         * 开始Debug SpringApplication.run 之旅
         * 1. SpringApplication.java
         *
         *     public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
         *         return run(new Class[]{primarySource}, args);
         *     }
         *
         * 2. SpringApplication.java :创建返回ConfigurableApplicationContext对象
         *
         *   public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
         *       return (new SpringApplication(primarySources)).run(args);
         *    }
         *
         * 3. SpringApplication.java ：【可忽略大部分源码，找最重要的部分】
         *
         *  public ConfigurableApplicationContext run(String... args) {
         *         StopWatch stopWatch = new StopWatch();
         *         stopWatch.start();
         *         DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
         *         ConfigurableApplicationContext context = null;
         *         this.configureHeadlessProperty();
         *         SpringApplicationRunListeners listeners = this.getRunListeners(args);
         *         listeners.starting(bootstrapContext, this.mainApplicationClass);
         *
         *         Throwable ex;
         *         try {
         *             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
         *             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
         *             this.configureIgnoreBeanInfo(environment);
         *             Banner printedBanner = this.printBanner(environment);
         *             context = this.createApplicationContext(); //！！！严重分析 ：创建容器
         *             context.setApplicationStartup(this.applicationStartup);
         *             this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
         *             this.refreshContext(context);//！！！严重分析：刷新应用程序的上下文，比如初始化默认设置/启动tomat
         *             this.afterRefresh(context, applicationArguments);
         *             stopWatch.stop();
         *             if (this.logStartupInfo) {
         *                 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
         *             }
         *
         *             listeners.started(context);
         *             this.callRunners(context, applicationArguments);
         *         } catch (Throwable var10) {
         *             ex = var10;
         *             this.handleRunFailure(context, ex, listeners);
         *             throw new IllegalStateException(ex);
         *         }
         *
         *         try {
         *             listeners.running(context);
         *             return context;
         *         } catch (Throwable var9) {
         *             ex = var9;
         *             this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
         *             throw new IllegalStateException(ex);
         *         }
         *     }
         *
         * 4.  SpringApplication.java ：容器类型有很多，他会根据你的this.webApplicationType创建对应的容器
         *     默认this.webApplicationType 是 SERVLET 也就是web容器/可以处理servlet
         *
         *     protected ConfigurableApplicationContext createApplicationContext() {
         *         return this.applicationContextFactory.create(this.webApplicationType);
         *     }
         *
         *  5. ApplicationContextFactory.java
         *
         *  ApplicationContextFactory DEFAULT = (webApplicationType) -> {
         *         try {
         *             switch (webApplicationType) {
         *                 case SERVLET://默认是会进入到这个分支，返回 AnnotationConfigServletWebServerApplicationContext容器
         *                     return new AnnotationConfigServletWebServerApplicationContext();
         *                 case REACTIVE:
         *                     return new AnnotationConfigReactiveWebServerApplicationContext();
         *                 default:
         *                     return new AnnotationConfigApplicationContext();
         *             }
         *         } catch (Exception var2) {
         *             Exception ex = var2;
         *             throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", ex);
         *         }
         *     };
         *
         *  6.  SpringApplication.java
         *
         *      private void refreshContext(ConfigurableApplicationContext context) {
         *         if (this.registerShutdownHook) {
         *             shutdownHook.registerApplicationContext(context);
         *         }
         *         this.refresh(context); //严重分析：真正执行刷新工作
         *     }
         *
         *     7.SpringApplication.java
         *
         *         protected void refresh(ConfigurableApplicationContext applicationContext) {
         *         applicationContext.refresh();
         *     }
         *
         *     8.ServletWebServerApplicationContext.java
         *
         *         public final void refresh() throws BeansException, IllegalStateException {
         *         try {
         *             super.refresh();//会由它的父类完成刷新方法【因为容器有很多种，这些都需要刷新，所以就交给它的父类】
         *         } catch (RuntimeException var3) {
         *             RuntimeException ex = var3;
         *             WebServer webServer = this.webServer;
         *             if (webServer != null) {
         *                 webServer.stop();
         *             }
         *
         *             throw ex;
         *         }
         *     }
         *
         *   9.AbstractApplicationContext.java
         *
         *   public void refresh() throws BeansException, IllegalStateException {
         *         synchronized(this.startupShutdownMonitor) {
         *             StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
         *             this.prepareRefresh();
         *             ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
         *             this.prepareBeanFactory(beanFactory);
         *
         *             try {
         *                 this.postProcessBeanFactory(beanFactory);
         *                 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         *                 this.invokeBeanFactoryPostProcessors(beanFactory);
         *                 this.registerBeanPostProcessors(beanFactory);
         *                 beanPostProcess.end();
         *                 this.initMessageSource();
         *                 this.initApplicationEventMulticaster();
         *                 this.onRefresh();//严重分析：当父类完成通用的工作后，再重新使用动态绑定机制回到子类
         *                 this.registerListeners();
         *                 this.finishBeanFactoryInitialization(beanFactory);
         *                 this.finishRefresh();
         *             } catch (BeansException var10) {
         *                 BeansException ex = var10;
         *                 if (this.logger.isWarnEnabled()) {
         *                     this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
         *                 }
         *
         *                 this.destroyBeans();
         *                 this.cancelRefresh(ex);
         *                 throw ex;
         *             } finally {
         *                 this.resetCommonCaches();
         *                 contextRefresh.end();
         *             }
         *
         *         }
         *     }
         *
         *   10.ServletWebServerApplicationContext.java
         *
         *         protected void onRefresh() {
         *         super.onRefresh();
         *
         *         try {
         *             this.createWebServer(); //创建webserver 可以理解成会创建指定的web服务器-->tomat
         *         } catch (Throwable var2) {
         *             Throwable ex = var2;
         *             throw new ApplicationContextException("Unable to start web server", ex);
         *         }
         *     }
         *
         *   11. ServletWebServerApplicationContext.java
         *
         *    private void createWebServer() {
         *         WebServer webServer = this.webServer;
         *         ServletContext servletContext = this.getServletContext();
         *         if (webServer == null && servletContext == null) {
         *             StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
         *             ServletWebServerFactory factory = this.getWebServerFactory();
         *             createWebServer.tag("factory", factory.getClass().toString());
         *             this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});//严重分析：使用tomcat...Factory 创建一个TomcatWebServer
         *             createWebServer.end();
         *             this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
         *             this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
         *         } else if (servletContext != null) {
         *             try {
         *                 this.getSelfInitializer().onStartup(servletContext);
         *             } catch (ServletException var5) {
         *                 ServletException ex = var5;
         *                 throw new ApplicationContextException("Cannot initialize servlet context", ex);
         *             }
         *         }
         *
         *         this.initPropertySources();
         *     }
         *
         *     12.TomcatServletWebServerFactory.java  会创建tomcat
         *
         *     public WebServer getWebServer(ServletContextInitializer... initializers) {
         *         if (this.disableMBeanRegistry) {
         *             Registry.disableRegistry();
         *         }
         *
         *         Tomcat tomcat = new Tomcat();//创建tomcat
         *         File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
         *         //做了一系列设置
         *         tomcat.setBaseDir(baseDir.getAbsolutePath());
         *         Connector connector = new Connector(this.protocol);
         *         connector.setThrowOnFailure(true);
         *         tomcat.getService().addConnector(connector);
         *         this.customizeConnector(connector);
         *         tomcat.setConnector(connector);
         *         tomcat.getHost().setAutoDeploy(false);
         *         this.configureEngine(tomcat.getEngine());
         *         Iterator var5 = this.additionalTomcatConnectors.iterator();
         *
         *         while(var5.hasNext()) {
         *             Connector additionalConnector = (Connector)var5.next();
         *             tomcat.getService().addConnector(additionalConnector);
         *         }
         *
         *         this.prepareContext(tomcat.getHost(), initializers);
         *         return this.getTomcatWebServer(tomcat);//严重分析：该方法一定包含了启动tomcat的方法
         *     }
         *
         *   13.TomcatServletWebServerFactory.java，这里做了校验并创建了TomcatWebServer【判断端口如果小于0就会直接关闭】
         *
         *       protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
         *         return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
         *     }
         *
         *   14.TomcatWebServer.java
         *
         *       public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
         *         this.monitor = new Object();
         *         this.serviceConnectors = new HashMap();
         *         Assert.notNull(tomcat, "Tomcat Server must not be null");
         *         this.tomcat = tomcat;
         *         this.autoStart = autoStart;
         *         this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
         *         this.initialize();//严重分析这个方法，会进行tomcat的初始与启动
         *     }
         *
         *   15.TomcatWebServer.java
         *
         *         private void initialize() throws WebServerException {
         *         logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
         *         synchronized(this.monitor) {
         *             try {
         *                 this.addInstanceIdToEngineName();
         *                 Context context = this.findContext();
         *                 context.addLifecycleListener((event) -> {
         *                     if (context.equals(event.getSource()) && "start".equals(event.getType())) {
         *                         this.removeServiceConnectors();
         *                     }
         *
         *                 });
         *                 this.tomcat.start();//启动tomcat【最终目标找到了】
         *                 this.rethrowDeferredStartupExceptions();
         *
         *                 try {
         *                     ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
         *                 } catch (NamingException var5) {
         *                 }
         *
         *                 this.startDaemonAwaitThread();
         *             } catch (Exception var6) {
         *                 Exception ex = var6;
         *                 this.stopSilently();
         *                 this.destroySilently();
         *                 throw new WebServerException("Unable to start embedded Tomcat", ex);
         *             }
         *
         *         }
         *     }
         */
        ConfigurableApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);
        System.out.println("hello ioc");
    }
}
